package com.sikulifang.bank.simulation.server.service.impl;

import com.sikulifang.bank.simulation.persistence.Bank;
import com.sikulifang.bank.simulation.server.handler.PortUnificationServerHandler;
import com.sikulifang.bank.simulation.server.service.IServerHandler;
import com.sikulifang.bank.simulation.util.OsHelper;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;


/**
 * 代理服务控制实现类
 *
 * @author zhoul
 */
@Slf4j
public class ServerHandlerImpl implements IServerHandler {

    @Getter
    private final Bank bank;
    @Setter
    private ApplicationContext applicationContext;
    private Channel channel;

    public ServerHandlerImpl(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void start() {
        EventLoopGroup bossGroup = OsHelper.buildEventLoopGroup(1);
        int ioWorkerCount = Runtime.getRuntime().availableProcessors() * 2;
        EventLoopGroup workerGroup = OsHelper.buildEventLoopGroup(ioWorkerCount);

        Integer listenPort = bank.getPort();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(OsHelper.serverSocketChannelClazz())
                    .option(ChannelOption.SO_BACKLOG, 10240)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            PortUnificationServerHandler portUnificationServerHandler =
                                    new PortUnificationServerHandler();
                            portUnificationServerHandler.setApplicationContext(applicationContext);
                            portUnificationServerHandler.setBank(bank);
                            ch.pipeline().addLast(portUnificationServerHandler);
                        }
                    });
            Channel channel = bootstrap.bind(listenPort).sync().channel();
            log.info("started [{}] netty listening on port: {}", bank.getCode(), listenPort);
            this.channel = channel;
            // 监听器异步处理销毁线程组
            this.channel.closeFuture().addListener(future -> {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
                log.info("stop [{}] netty listening on port: {}", bank.getCode(), listenPort);
            });
        } catch (Exception e) {
            log.error("started [{}] netty on port: {} failure, reason:{}", bank.getCode(), listenPort, e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void close() {
        if (this.channel != null) {
            channel.close();
        }
    }
}
